home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / russell / gc.lha / test.c < prev   
C/C++ Source or Header  |  1993-04-26  |  9KB  |  385 lines

  1. /* An incomplete test for the garbage collector.          */
  2. /* Some more obscure entry points are not tested at all.    */
  3. # include <stdlib.h>
  4. # include <stdio.h>
  5. # include "gc.h"
  6. # ifdef PCR
  7. #   include "th/PCR_ThCrSec.h"
  8. #   include "th/PCR_Th.h"
  9. # endif
  10.  
  11. /* AT_END may be defined to excercise the interior pointer test    */
  12. /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
  13. /* As it stands, this test should succeed with either        */
  14. /* configuration.  In the FIND_LEAK configuration, it should    */
  15. /* find lots of leaks, since we free almost nothing.        */
  16.  
  17. struct SEXPR {
  18.     struct SEXPR * sexpr_car;
  19.     struct SEXPR * sexpr_cdr;
  20. };
  21.  
  22. # ifdef __STDC__
  23.     typedef void * void_star;
  24. # else
  25.     typedef char * void_star;
  26. # endif
  27.  
  28. typedef struct SEXPR * sexpr;
  29.  
  30. extern sexpr cons();
  31.  
  32. # define nil ((sexpr) 0)
  33. # define car(x) ((x) -> sexpr_car)
  34. # define cdr(x) ((x) -> sexpr_cdr)
  35. # define is_nil(x) ((x) == nil)
  36.  
  37.  
  38. int extra_count = 0;        /* Amount of space wasted in cons node */
  39.  
  40. /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
  41. /* to test collector.                                                    */
  42. sexpr cons (x, y)
  43. sexpr x;
  44. sexpr y;
  45. {
  46.     register sexpr r;
  47.     register int *p;
  48.     register my_extra = extra_count;
  49.     
  50.     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR) + my_extra);
  51.     if (r == 0) {
  52.         (void)printf("Out of memory\n");
  53.         exit(1);
  54.     }
  55.     for (p = (int *)r;
  56.          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
  57.     if (*p) {
  58.         (void)printf("Found nonzero at %X\n - allocator is broken", p);
  59.         exit(1);
  60.         }
  61.         *p = 13;
  62.     }
  63. #   ifdef AT_END
  64.     r = (sexpr)((char *)r + (my_extra & ~7));
  65. #   endif
  66.     r -> sexpr_car = x;
  67.     r -> sexpr_cdr = y;
  68.     extra_count = (my_extra + 1) % 5000;
  69.     return(r);
  70. }
  71.  
  72. sexpr small_cons (x, y)
  73. sexpr x;
  74. sexpr y;
  75. {
  76.     register sexpr r;
  77.     register int *p;
  78.     
  79.     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
  80.     if (r == 0) {
  81.         (void)printf("Out of memory\n");
  82.         exit(1);
  83.     }
  84.     r -> sexpr_car = x;
  85.     r -> sexpr_cdr = y;
  86.     return(r);
  87. }
  88.  
  89.  
  90. /* Return reverse(x) concatenated with y */
  91. sexpr reverse1(x, y)
  92. sexpr x, y;
  93. {
  94.     if (is_nil(x)) {
  95.         return(y);
  96.     } else {
  97.         return( reverse1(cdr(x), cons(car(x), y)) );
  98.     }
  99. }
  100.  
  101. sexpr reverse(x)
  102. sexpr x;
  103. {
  104.     return( reverse1(x, nil) );
  105. }
  106.  
  107. sexpr ints(low, up)
  108. int low, up;
  109. {
  110.     if (low > up) {
  111.     return(nil);
  112.     } else {
  113.         return(small_cons(small_cons((sexpr)low, 0), ints(low+1, up)));
  114.     }
  115. }
  116.  
  117. void check_ints(list, low, up)
  118. sexpr list;
  119. int low, up;
  120. {
  121.     if ((int)(car(car(list))) != low) {
  122.         (void)printf(
  123.            "List reversal produced incorrect list - collector is broken\n");
  124.         exit(1);
  125.     }
  126.     if (low == up) {
  127.         if (cdr(list) != nil) {
  128.            (void)printf("List too long - collector is broken\n");
  129.            exit(1);
  130.         }
  131.     } else {
  132.         check_ints(cdr(list), low+1, up);
  133.     }
  134. }
  135.  
  136. /* Not used, but useful for debugging: */
  137. void print_int_list(x)
  138. sexpr x;
  139. {
  140.     if (is_nil(x)) {
  141.         (void)printf("NIL\n");
  142.     } else {
  143.         (void)printf("(%d)", car(car(x)));
  144.         if (!is_nil(cdr(x))) {
  145.             (void)printf(", ");
  146.             (void)print_int_list(cdr(x));
  147.         } else {
  148.             (void)printf("\n");
  149.         }
  150.     }
  151. }
  152.  
  153. /* Try to force a to be strangely aligned */
  154. struct {
  155.   char dummy;
  156.   sexpr aa;
  157. } A;
  158. #define a A.aa
  159.  
  160. /*
  161.  * Repeatedly reverse lists built out of very different sized cons cells.
  162.  * Check that we didn't lose anything.
  163.  */
  164. reverse_test()
  165. {
  166.     int i;
  167.     sexpr b;
  168.     sexpr c;
  169.  
  170.     a = ints(1, 100);
  171.     b = ints(1, 50);
  172.     c = ints(1, 4500);
  173.     for (i = 0; i < 50; i++) {
  174.         b = reverse(reverse(b));
  175.     }
  176.     for (i = 0; i < 10; i++) {
  177.         /* This maintains the invariant that a always points to a list of */
  178.         /* 100 integers.  Thus this is thread safe without locks.      */
  179.         a = reverse(reverse(a));
  180. #    if !defined(AT_END) && !defined(PCR)
  181.       /* This is not thread safe, since realloc explicitly deallocates */
  182.           if (i & 1) {
  183.             a = (sexpr)GC_REALLOC((void_star)a, 500);
  184.           } else {
  185.             a = (sexpr)GC_REALLOC((void_star)a, 4200);
  186.           }
  187. #    endif
  188.     }
  189.     check_ints(a,1,100);
  190.     check_ints(b,1,50);
  191.     check_ints(c,1,4500);
  192.     a = b = c = 0;
  193. }
  194.  
  195. /*
  196.  * The rest of this builds balanced binary trees, checks that they don't
  197.  * disappear, and tests finalization.
  198.  */
  199. typedef struct treenode {
  200.     int level;
  201.     struct treenode * lchild;
  202.     struct treenode * rchild;
  203. } tn;
  204.  
  205. int finalizable_count = 0;
  206. int finalized_count = 0;
  207. int dropped_something = 0;
  208.  
  209. # ifdef __STDC__
  210.   void finalizer(void * obj, void * client_data)
  211. # else
  212.   void finalizer(obj, client_data)
  213.   char * obj;
  214.   char * client_data;
  215. # endif
  216. {
  217.   tn * t = (tn *)obj;
  218.   if ((int)client_data != t -> level) {
  219.      (void)printf("Wrong finalization data - collector is broken\n");
  220.      exit(1);
  221.   }
  222.   finalized_count++;
  223. }
  224.  
  225. size_t counter = 0;
  226.  
  227. tn * mktree(n)
  228. int n;
  229. {
  230.     tn * result = (tn *)GC_MALLOC(sizeof(tn));
  231.     
  232.     if (n == 0) return(0);
  233.     if (result == 0) {
  234.         (void)printf("Out of memory\n");
  235.         exit(1);
  236.     }
  237.     result -> level = n;
  238.     result -> lchild = mktree(n-1);
  239.     result -> rchild = mktree(n-1);
  240.     if (counter++ % 119 == 0) {
  241.         GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
  242.                       (GC_finalization_proc *)0, (void_star *)0);
  243. #    ifdef PCR
  244.          PCR_ThCrSec_EnterSys();
  245.          /* Losing a count here causes erroneous report of failure. */
  246. #    endif
  247.         finalizable_count++;
  248. #    ifdef PCR
  249.          PCR_ThCrSec_ExitSys();
  250. #    endif
  251.     }
  252.     return(result);
  253. }
  254.  
  255. void chktree(t,n)
  256. tn *t;
  257. int n;
  258. {
  259.     if (n == 0 && t != 0) {
  260.         (void)printf("Clobbered a leaf - collector is broken\n");
  261.         exit(1);
  262.     }
  263.     if (n == 0) return;
  264.     if (t -> level != n) {
  265.         (void)printf("Lost a node at level %d - collector is broken\n", n);
  266.         exit(1);
  267.     }
  268.     if (counter++ % 373 == 0) (void) GC_MALLOC(counter%5001);
  269.     chktree(t -> lchild, n-1);
  270.     if (counter++ % 73 == 0) (void) GC_MALLOC(counter%373);
  271.     chktree(t -> rchild, n-1);
  272. }
  273.  
  274. void alloc_small(n)
  275. int n;
  276. {
  277.     register int i;
  278.     
  279.     for (i = 0; i < n; i += 8) {
  280.         if (GC_MALLOC_ATOMIC(8) == 0) {
  281.             (void)printf("Out of memory\n");
  282.             exit(1);
  283.         }
  284.     }
  285. }
  286.  
  287. tree_test()
  288. {
  289.     tn * root = mktree(16);
  290.     register int i;
  291.     
  292.     alloc_small(5000000);
  293.     chktree(root, 16);
  294.     if (finalized_count && ! dropped_something) {
  295.         (void)printf("Premature finalization - collector is broken\n");
  296.         exit(1);
  297.     }
  298.     dropped_something = 1;
  299.     root = mktree(16);
  300.     chktree(root, 16);
  301.     for (i = 16; i >= 0; i--) {
  302.         root = mktree(i);
  303.         chktree(root, i);
  304.     }
  305.     alloc_small(5000000);
  306. }
  307.  
  308. # include "gc_private.h"
  309.  
  310. int n_tests = 0;
  311.  
  312. void run_one_test()
  313. {
  314.     DCL_LOCK_STATE;
  315.     
  316.     reverse_test();
  317.     tree_test();
  318.     LOCK();
  319.     n_tests++;
  320.     UNLOCK();
  321.     
  322. }
  323.  
  324. void check_heap_stats()
  325. {
  326.     (void)printf("Completed %d tests\n", n_tests);
  327.     (void)printf("Finalized %d/%d objects - ",
  328.              finalized_count, finalizable_count);
  329.     if (finalized_count > finalizable_count
  330.         || finalized_count < finalizable_count/2) {
  331.         (void)printf ("finalization is probably broken\n");
  332.         exit(1);
  333.     } else {
  334.         (void)printf ("finalization is probably ok\n");
  335.     }
  336.     (void)printf("Total number of bytes allocated is %d\n",
  337.                  WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
  338.     (void)printf("Final heap size is %d bytes\n", GC_heapsize);
  339.     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
  340.         < 33500000*n_tests) {
  341.         (void)printf("Incorrect execution - missed some allocations\n");
  342.         exit(1);
  343.     }
  344.     if (GC_heapsize > 10000000*n_tests) {
  345.         (void)printf("Unexpected heap growth - collector may be broken\n");
  346.         exit(1);
  347.     }
  348.     (void)printf("Collector appears to work\n");
  349. }
  350.  
  351. #ifndef PCR
  352. main()
  353. {
  354.     n_tests = 0;
  355.     run_one_test();
  356.     check_heap_stats();
  357.     (void)fflush(stdout);
  358.     return(0);
  359. }
  360. # else
  361. test()
  362. {
  363.     PCR_Th_T * th1;
  364.     PCR_Th_T * th2;
  365.     int code;
  366.  
  367.     n_tests = 0;
  368.     th1 = PCR_Th_Fork(run_one_test, 0);
  369.     th2 = PCR_Th_Fork(run_one_test, 0);
  370.     run_one_test();
  371.     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  372.         != PCR_ERes_okay || code != 0) {
  373.         (void)printf("Thread 1 failed\n");
  374.     }
  375.     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  376.         != PCR_ERes_okay || code != 0) {
  377.         (void)printf("Thread 2 failed\n");
  378.     }
  379.     check_heap_stats();
  380.     (void)fflush(stdout);
  381.     return(0);
  382. }
  383. #endif
  384.  
  385.